﻿using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace ControlLibrary.ComponentModel {
    internal class ActionListBase : DesignerActionList {
        private object boundSelectedValue;
        internal readonly IComponent LinkedControl;
        internal readonly ControlDesigner ControlOwner;

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="component"></param>
        /// <param name="controlDesigner"></param>
        public ActionListBase(IComponent component, ControlDesigner controlDesigner)
            : base(component) {
            ControlOwner = controlDesigner;
            LinkedControl = component;
        }

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="propName"></param>
        /// <returns></returns>
        internal PropertyDescriptor GetPropertyByName(string propName) {
            var prop = TypeDescriptor.GetProperties(LinkedControl)[propName];
            if (null == prop) {
                throw new ArgumentException("Matching property not found.", propName);
            }

            return prop;
        }

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="linkControlProp"></param>
        /// <param name="value"></param>
        /// <param name="currentPropName"></param>
        internal void SetBind(string linkControlProp, object value, string currentPropName) {
            if (value is String) {
                var pd = TypeDescriptor.GetProperties(this)[currentPropName];
                var tc = pd.Converter;
                boundSelectedValue = tc.ConvertFrom(new EditorServiceContextEx(ControlOwner), CultureInfo.InvariantCulture, value);
            } else {
                boundSelectedValue = value;
                if (value != null) {
                    var dataSource = TypeDescriptor.GetProperties(boundSelectedValue)["DataSource"].GetValue(boundSelectedValue);
                    var dataMember = (string)TypeDescriptor.GetProperties(boundSelectedValue)["DataMember"].GetValue(boundSelectedValue);
                    SetSelectedValueBinding(linkControlProp, dataSource, dataMember);
                }
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        internal object GetBind(string propertyName) {
            var b = GetSelectedValueBinding(propertyName);
            string dataMember;
            object dataSource;
            if (b == null) {
                dataMember = null;
                dataSource = null;
            } else {
                dataMember = b.BindingMemberInfo.BindingMember;
                dataSource = b.DataSource;
            }
            var typeName = string.Format(CultureInfo.InvariantCulture, "System.Windows.Forms.Design.DesignBinding, {0}", typeof(ControlDesigner).Assembly.FullName);
            boundSelectedValue = TypeDescriptor.CreateInstance(null, Type.GetType(typeName), new[] { typeof(object), typeof(string) }, new[] { dataSource, dataMember });

            return boundSelectedValue;
        }

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="linkControlProp"></param>
        /// <param name="dataSource"></param>
        /// <param name="dataMember"></param>
        private void SetSelectedValueBinding(string linkControlProp, object dataSource, string dataMember) {
            var listControl = (Control)ControlOwner.Component;
            var host = GetService(typeof(IDesignerHost)) as IDesignerHost;
            var changeService = GetService(typeof(IComponentChangeService)) as IComponentChangeService;
            var dataSourceProp = TypeDescriptor.GetProperties(listControl)["DataBindings"];

            if (host != null && changeService != null) {
                using (var transaction = host.CreateTransaction("TextBox DataSource RESX")) {
                    changeService.OnComponentChanging(ControlOwner.Component, dataSourceProp);

                    var foundBinding = GetSelectedValueBinding(linkControlProp);

                    if (foundBinding != null) {
                        listControl.DataBindings.Remove(foundBinding);
                    }
                    if (listControl.DataBindings != null) {
                        if (dataSource != null && !String.IsNullOrEmpty(dataMember)) {
                            listControl.DataBindings.Add(linkControlProp, dataSource, dataMember);
                        }
                    }

                    changeService.OnComponentChanged(ControlOwner.Component, dataSourceProp, null, null);

                    transaction.Commit();
                }
            } else {
                Debug.Fail("Could not get either IDEsignerHost or IComponentChangeService");
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        private Binding GetSelectedValueBinding(string propertyName) {
            var listControl = (Control)Component;
            Binding foundBinding = null;
            if (listControl.DataBindings != null) {
                foreach (Binding binding in listControl.DataBindings) {
                    if (binding.PropertyName == propertyName)
                        foundBinding = binding;
                }
            }
            return foundBinding;
        }
    }
}
